/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package CTRL;

/**
 *
 * @author Renaud & François & Karen
 *
 * protocol coté client
 */
import commun.Bille;
import commun.Pions;
import java.io.*;
import java.net.Socket;

public class Protocol {

    private OutputStream flux;
    private InputStream entree;
    private BufferedReader reception;
    private PrintWriter envoi;
    private Socket s;
    private int port;
    private String ip;

// ici tous les messages qui seront traités et traduits par le protocole  
    // on crée une instance de la classe port, mais on ne fait pas de connexion.
    public Protocol(int port, String ip) {
        this.ip = ip;
        this.port = port;

    }

    // on connecte client au serveur seulement quand on en a besoin
    // par la suite il faut implementer les erreurs... 
    @SuppressWarnings("SleepWhileInLoop")  // pas compris la signification du truc
    public void connect() throws IOException {
        boolean con = false;
        while (con == false) {
            try {
                s = new Socket(ip, port);
                flux = s.getOutputStream();
                entree = s.getInputStream();
                reception = new BufferedReader(new InputStreamReader(entree));
                envoi = new PrintWriter(flux, true);
                con = true;
            } catch (Exception e) {
                System.out.print(". ");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ex) {
                }
            }

        }
    }

    // on arrete la connexion.
    public void stopSocket() throws IOException {
        s.close();
        //   System.out.println("Socket fermé");
    }

    // envoie d'un Int
    private void sendInt(int integer) throws IOException {
        envoi.write(integer);
        envoi.flush();
    }
    // envoie d'un STring

    private void sendStr(String str) {
        envoi.println(str);
        //  envoi.write(str+'\n'); 
        envoi.flush();
    }

    // msg pour le serveur  OK,
    private void sendOK() {
        envoi.println("OK");
        envoi.flush();
    }

    // msg pour le serveur NOK
    private void sendNOK() {
        envoi.println("NOK");
        envoi.flush();
    }
    // reception d'un OK du serveur

    public boolean recuOK() throws IOException {
        boolean out = true;
        String rep = reception.readLine();
        if (rep.equals("OK") == false) {
            out = false;
        }
        return out;
    }

    // envoi de la combinaison vers serveur
    private void envoiGrille(Bille[] combi) {
        envoi.println(toString(combi));
        envoi.flush();
    }

    // representation en chaine de la combinaison
    private String toString(Bille[] toTransform) {
        String convert;

        int offset = toTransform.length;
        convert = toTransform[0].name();
        for (int i = 1; i < offset; i++) {
            convert = convert + "-" + toTransform[i].name();
        }
        return convert;
    }

    //  creation d'une nouvelle partie (envoie du msg au server ainsi que les configs et reception ID)
    // colors => nombre de choix de couleurs
    // size la taille de la combinaison des billes
    public int newPartie(int size, int colors) throws IOException {  // 
        int id;
        connect();
        //envoie du "nouvelle partie" pour indiquer au serveur que c'est une nouvelle demande
        sendStr("nouvelle partie");
        sendInt(size);    // nb de choix de billes
        sendInt(colors);  // nb de choix de couleurs
        // 
        id = reception.read(); // receptions d'ID
        stopSocket();
        return id;
    }

    // creation de la partie pour un user donéée dans une table de hachage sur serveur
    public void createPartie(String user, int nbColons, int nbColors, int nbTent) throws IOException {
        connect();
        // demande de creation de partie sur serveur pour user donné
        // à implementer dans Serveur
        sendStr("creation partie");
        sendStr(user);
        sendInt(nbColons);    // nb de choix de billes
        sendInt(nbColors);  // nb de choix de couleurs
        sendInt(nbTent);  // nb de tentatives max
        stopSocket();
    }

    public void reConfig(int id, int colors, int size) throws IOException {
        connect();
        sendStr("nouvelle configuration"); // envoie msg pour nouvelle config
        sendInt(id);        // envoie id de la partie concernée
        sendInt(size);    // nb de choix de billes
        sendInt(colors);  // nb de choix de couleurs
        stopSocket();
    }
    // demande de refaire un nouveau secretCode ... :)

    public void reCode(int id) throws IOException {
        connect();
        sendStr("meme configuration"); // envoie msg pour nouvelle config
        sendInt(id);        // envoie id de la partie concernée
        stopSocket();
    }

    //  envoie ID de user existant +  la combinaison + reception de pions
    public Pions sendCombi(int id, Bille[] combi) throws IOException {
        // nouvelle connexion 
        connect();
        Pions out = new Pions();
        //envoi.write("userId");
        sendStr("verifier combinaison");  // msg pour serveur
        sendInt(id);                 // envoie id de la partie concernée        
        //  utilisation de la procedure existante qui transforme et envoie la combinaison
        envoiGrille(combi);
        // reception des pions. pas besoin de transformer ==>only INT
        out.setNoir(reception.read());  // on recoit les noirs
        out.setBlanc(reception.read()); // on recoit les blancs
        stopSocket(); //  
        return out;

    }
    // ceci remplace la procedure " Pions sendCombi (....) 
    // elle perment d'avoir en plus des pions l'info sur win.
    // evite une double connexion. +  d'info dans fichier info.ini

    public String[] sendCombi(int id, Bille[] combi, int numTourC) throws IOException {
        // nouvelle connexion 
        connect();
        String[] out = new String[3];  // ou juste String [] out; ?????

        sendStr("verifier combinaison int");  // msg pour serveur
        sendInt(id);                   // envoie le nom du joueur        
        //  utilisation de la procedure existante qui transforme et envoie la combinaison
        envoiGrille(combi);

        sendInt(numTourC); // envoie du noumero du tour courant
        // reception des pions. +  win
        out[0] = reception.readLine();  // on recoit les noirs
        out[1] = reception.readLine();  // on recoit les blancs
        out[2] = reception.readLine();  // on recoit win

        stopSocket(); //  
        return out;
    }

    //--- à implementer  dans serveur
    // -- permet d'avoir les pions et reccuperer win
    public String[] sendCombi(String uName, Bille[] combi, int numTourC) throws IOException {
        // nouvelle connexion
        connect();
        String[] out = new String[4];  // ou juste String [] out; ?????

        sendStr("verifier combinaison user");  // msg pour serveur
        sendStr(uName);                   // envoie le nom du joueur        
        //  utilisation de la procedure existante qui transforme et envoie la combinaison
        envoiGrille(combi);

        sendInt(numTourC); // envoie du noumero du tour courant
        // reception des pions. +  win
        out[0] = reception.readLine();  // on recoit les noirs
        out[1] = reception.readLine();  // on recoit les blancs
        out[2] = reception.readLine();  // on recoit win
        out[3] = reception.readLine();  //  score
        stopSocket(); //  
        return out;
    }

    // ne sera plus utilisé
    public boolean win(int id) throws IOException {
        boolean out = false;


        connect();
        System.out.println("envoie WIN");
        sendStr("win");  // msg pour serveur
        sendInt(id);     // envoie id de la partie concernée 
        String rep = reception.readLine();
        System.out.println("reçu REP " + rep);
        if (rep.equals("OK") == true) { // 
            out = true;
            System.out.println("reçu True");
        }

        stopSocket(); // 
        return out;

    }

    // login => connexion au serveur => qui est en fait une verification si user existe et si son pass est correct
    public boolean logIn(String user, String pass) throws IOException { // Log In  si error => user n'existe pas ou pass error
        boolean out = false;
        connect();
        sendStr("log In");  // msg pour serveur
        sendStr(user);         // nom de user
        sendStr(pass);          // send pass
        String rep = reception.readLine();
        if (rep.equals("OK") == true) { // 
            out = true;
            //System.out.println("reçu True"); // à cacher
        }
        stopSocket(); //
        return out;
    }

    // new user creation d'un nouvau utilisateur sur serveur BD
    public boolean newUser(String user, String pass) throws IOException {
        boolean out = false;
        connect();
        sendStr("newUser");  // msg pour serveur
        sendStr(user);         // nom de user à creer
        sendStr(pass);          // send pass
        String rep = reception.readLine();  // recoit ok si creation reussi et  NOK si user exist
        if (rep.equals("OK") == true) { //   
            out = true;
            System.out.println("reçu True"); // à cacher
        }
        stopSocket(); //
        return out;
    }

// demande de stats (top 10) d'une confige donnée
    public String[] getStats(int typeconf) throws IOException {
        connect();


        sendStr("getStats");	 // message pour indique ce qu'on veut faire
        sendInt(typeconf); 	 // type de config
        String[] out = new String[reception.read()];  // on crée  le STRING []  de bonne taille
        for (int i = 0; i < out.length; i++) {
            out[i] = reception.readLine(); //  la ligne à afficher, (un string concat, separé par des espaces)
            //    NOM config Score (et même config pas specialement besoin)
        }
        stopSocket();
        return out;
    }

    // demande de stats pour un utilisateur donnée
    public String[] getStats(String name) throws IOException {
        connect();

        sendStr("getUserStats");	 // message pour indique ce qu'on veut faire
        sendStr(name);           // nom du user en queston 

        String[] out = new String[reception.read()];  // on crée  le STRING []  de bonne taille

        for (int i = 0; i < out.length; i++) {
            out[i] = reception.readLine(); //  la ligne à afficher, (un string concat, separé par des espaces)
        }
        stopSocket();
        return out;
    }
}
